// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: qiang

#pragma once

#include <memory>
#include <string>
#include <unordered_map>

#include "coin2/exchange/apollox_base/api_util/auth_key.h"
#include "coin2/exchange/apollox_base/api_util/rate_tracker.h"
#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/order/apollox.pb.h"

class ApolloxNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::ApolloxRestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using RestQueryProto = coin2::exchange::base::order::RestQueryProto;
  using ApolloxRateTracker = coin2::exchange::apollox::api_util::ApolloxRateTracker;
  using AsioHttpContextList = std::list<std::shared_ptr<AsioHttpContext>>;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);

 public:
  explicit ApolloxNativePrivateClient(
      const MarketExchangeApi& mea,
      const NativeClientConfig& config);

  std::shared_ptr<AsioHttpContext> QueryAccountBalance(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOpenOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryAllOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryTrades(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> GenListenKey();

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;
  void Prepare() override;
  AsioHttpContextList SubmitRestQueryList(const RestQueryProto& query);
  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);

  std::string DebugString() const;

  std::string GetCurrMilliseconds() const {
    return std::to_string(GetCurrentTimestamp() / 1000000);
  }
  BaseRestAuth* GetAuth() const override;

 private:
  void SetBindIp(const std::string&);

 private:
  int64_t start_time_;
  std::unordered_map<std::string, int32_t> api_block_info_;
  std::unordered_map<std::string, int32_t> api_req_info_;
  bool is_first_query_account_balance_ = true;
  std::unordered_map<std::string, int64_t> query_open_orders_ts_map_;
};
